package com.qfedu.zf.user.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qfedu.zf.common.config.RabbitKeyConfig;
import com.qfedu.zf.common.config.RedisKeyConfig;
import com.qfedu.zf.common.param.GrowthAdd;
import com.qfedu.zf.common.param.MqMsg;
import com.qfedu.zf.common.param.UserAdd;
import com.qfedu.zf.common.param.UserLogin;
import com.qfedu.zf.common.utils.JwtUtil;
import com.qfedu.zf.common.vo.R;
import com.qfedu.zf.user.entity.Log;
import com.qfedu.zf.user.entity.User;
import com.qfedu.zf.user.mapper.LogMapper;
import com.qfedu.zf.user.mapper.UserMapper;
import com.qfedu.zf.user.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.qfedu.zf.common.config.RedisKeyConfig.LOGIN_UID_TOKEN;

/**
 * <p>
 * 1.用户表 服务实现类
 * </p>
 *
 * @author wgz
 * @since 2024-06-05
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {


    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LogMapper logMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 1.判断参数是否为空
     * 2.判断验证码是否匹配 redis
     * 3.判断手机号是否重复  账号是否重复
     * 4.密码加密 插入user表
     * 5.记录用户日志
     * 6.删除注册验证码
     * @param userAdd
     * @return
     */
    @Override
    public R register(HttpServletRequest request, UserAdd userAdd) {

        // 1.判断参数是否为空
        // StringUtils.isAnyEmpty 只要任意参数为空就要返回false
        if (userAdd ==null || StringUtils.isAnyEmpty(userAdd.getAccount(),userAdd.getCode(),userAdd.getPhone(),userAdd.getPassword())){

            return R.fail("参数错误");
        }

        // 2.判断验证码是否匹配 redis
        String redisCode = stringRedisTemplate.opsForValue().get(RedisKeyConfig.SMS_RCODE + userAdd.getPhone());

        if (!userAdd.getCode().equals(redisCode)){
            return R.fail("验证码错误");
        }

        // 3.判断手机号是否重复

        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("phone",userAdd.getPhone());

        List<User> userList = userMapper.selectList(userQueryWrapper);
        if (userList!=null && userList.size()>0){
            return R.fail("手机号用户");
        }


        // 4.密码加密 插入user表
        User user = new User();
        user.setPhone(userAdd.getPhone())
                .setAccount(userAdd.getAccount())
                .setStatus(1)
                .setPassword(SecureUtil.md5(userAdd.getPassword()))// 进行密码 加密
                .setCtime(new Date());

        int num = userMapper.insert(user);
        if (num<=0){
            return R.fail("注册失败");
        }

        // 5.记录用户日志
        Log log = new Log();

        log.setUserId(user.getId())
                .setMobile(userAdd.getPhone())
                .setInfo(userAdd.getPhone()+"用户注册")
                .setType("用户注册")
                .setIp(request.getRemoteHost())
                .setCtime(new Date());

        logMapper.insert(log);


//        6.删除注册验证码
        stringRedisTemplate.delete(RedisKeyConfig.SMS_RCODE + userAdd.getPhone());

        // 7.积分增加 发送消息
        MqMsg mqMsg = new MqMsg();
        mqMsg.setId(IdUtil.getSnowflakeNextId());
        mqMsg.setType(5);

        GrowthAdd growthAdd = new GrowthAdd();
        growthAdd.setUid(user.getId());
        growthAdd.setType("新用户注册");
        growthAdd.setGrowth(50);

        mqMsg.setMsg(growthAdd);

        rabbitTemplate.convertAndSend("", RabbitKeyConfig.Q_USER_GROWTH,mqMsg);

        return R.ok("注册成功");
    }

    /**
     * 使用 账号 + 密码登录
     * 1.判断参数是否为空
     * 2.判断账户是存在，可用
     * 3.判断登录次数是否超过三次
     *     如何记录用户登录超过三次？
     *     <uid  +  token,0>   存储到redis中
     *     <uid  +  token,0>   存储到redis中
     *     <uid  +  token,0>   存储到redis中
     *
     *     uid相同，token不同  ，此时我们查找以uid开头的key 就可以得到 登录次数
     *
     *     如何记录登录的用户  记录redis
     *     <token,User>      由于登陆时已经将token 返回给了前端，后续前端发起的所有请求都会携带token
     *     <token,User>
     *     <token,User>
     *
     * 4.验证用户 密码
     *
     * 5.生成token
     * 6.存储token
     * 7.记录登录日志
     * 8.返回token
     * @param userLogin
     * @return
     */
    @Override
    public R loginPass(UserLogin userLogin) {

        // 1.判断参数是否为空
        if(userLogin==null || StringUtils.isAnyEmpty(userLogin.getName(),userLogin.getPass())){
            return R.fail("参数错误");
        }

        //  2.判断账户是存在，可用
        String account = userLogin.getName();
        String password = userLogin.getPass();

        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("account",account);

        List<User> userList = userMapper.selectList(userQueryWrapper);
        if (userList == null || userList.size()==0){
            return R.fail("该用户不存在");
        }

        //  3.判断登录次数是否超过三次  需要用到 redis 和 token
        User user = userList.get(0); // 当前数据库用户

        Set<String> keys = stringRedisTemplate.keys(LOGIN_UID_TOKEN + user.getId() + "*");
        if (keys!=null &&  keys.size()>=30000){
            return R.fail("登录超过三次");
        }


        //4.验证用户 密码

        if (!user.getPassword().equals(SecureUtil.md5(password))){
            return R.fail("账号或密码错误");
        }


        //  5.生成token
        String jwt = JwtUtil.createJwt(user.getId(), account, user.getPhone());

        //  6.存储token
        //  key   id + token       可以计算该id登录的次数  ==》  key:lc:uid:用户id:令牌   value 时间戳
        //  key   token         记录该token 对应的用户信息 ====> key:lc:token:令牌     value 用户对象信息

        // 记录次数
        stringRedisTemplate.opsForValue().set(RedisKeyConfig.LOGIN_UID_TOKEN+user.getId()+":"+jwt,"",12*60*60, TimeUnit.SECONDS);

        redisTemplate.opsForValue().set(RedisKeyConfig.LOGIN_TOKEN+jwt,user,12*60*60, TimeUnit.SECONDS);


        //7.记录登录日志
        Log log = new Log();

        log.setUserId(user.getId())
                .setMobile(user.getPhone())
                .setInfo(user.getPhone()+"用户登录")
                .setType("用户登录")
//                .setIp(request.getRemoteHost())
                .setCtime(new Date());

        logMapper.insert(log);


        return R.ok(jwt);
    }

    /**
     * 1.从header中获取token
     * 2.更具token 获取用户信息
     * 3.删除改用相关的token、
     * 4. 响应前端
     * @param token
     * @return
     */
    @Override
    public R logout(String token) {

//        2.更具token 获取用户信息
        User user = (User) redisTemplate.opsForValue().get(RedisKeyConfig.LOGIN_TOKEN + token);
//        3.删除改用相关的token、
        redisTemplate.delete(RedisKeyConfig.LOGIN_TOKEN + token);
        stringRedisTemplate.delete(RedisKeyConfig.LOGIN_UID_TOKEN+user.getId()+":"+token);

        return R.ok("退出成功");
    }


    /**
     * 1.查询用户信息
     * listing页面展示用户
     * @param map
     * @return
     */
    @Override
    public R listingUser(Map<String, Object> map) {
        User user = userMapper.selectById((Serializable) map.get("userId"));
        if (user == null) {
            return R.fail("房东不存在");
        }
        return R.ok(user);
    }
}
